package com.owc.service;

import com.alibaba.fastjson.JSON;
import com.owc.common.enums.CallbackTypeEnum;
import com.owc.common.enums.ExceptionEnum;
import com.owc.common.exception.BadRequestException;
import com.owc.common.sdk.Client;
import com.owc.common.sdk.request.*;
import com.owc.common.sdk.response.*;
import com.owc.dao.UserWalletAddressMapper;
import com.owc.domain.entity.UserWalletAddress;
import com.owc.domain.entity.WithdrawFlow;
import com.owc.service.app.WalletService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;

/**
 * @Author Jackies
 * @Date 2019/12/12 22:04
 * @Description TODO://
 **/
@Service
@Slf4j
public class WalletServer {

    @Resource
    private UserWalletAddressMapper userWalletAddressMapper;

    /**
     * Create a new ETH wallet.
     * @return address
     */
    public String createETHWalletAddress() throws Exception {
        Client client = WalletService.buildClient();
        try {
            WalletResponse response = client.execute(new GetWalletRequest());
            if(!response.getSuccess()){
                log.warn("Generate wallet address failed. Wallet server response invalid. ");
                return null;
            }
            return response.getData().getAddress();
        } catch (Exception e) {
            log.error("Generate wallet address failed. throw exception message:[{}]",e.getMessage());
            throw e;
        }
    }

    /**
     * Create a new BTC wallet.
     * @return address
     */
    public String createBTCWalletAddress() {
        return "";//Wait impl....
    }

    /**
     * 获取平台钱包余额
     * @param chain   链名称
     * @param tokenName 代币名称
     */
    public BigDecimal getPlatformBalance(String chain, String tokenName) throws Exception {
        return getPlatformBalance(chain,tokenName,null);
    }

    /**
     * 获取钱包余额
     * @param chain      主链名称
     * @param tokenName  代币名称
     * @param address    钱包地址(不传则默认返回中间发币人的钱包余额)
     */
    public BigDecimal getPlatformBalance(String chain, String tokenName, String address) throws Exception {
        Client client = WalletService.buildClient();
        try {

            BalanceRequest request = new BalanceRequest();
            request.setChain(chain);
            request.setTokenName(tokenName);
            request.setAddress(address);

            BalanceResponse response = client.execute(request);
            if(!response.getSuccess()){
                return null;
            }
            return response.getData().getBalance();
        } catch (Exception e) {
            log.error("Generate wallet address failed. throw exception message:[{}]",e.getMessage());
            throw e;
        }
    }

    public CancelOrderResponse.ResponseMsgResult cancelOrder(String txHash) throws Exception {
        Client client = WalletService.buildClient();
        try {

            CancelOrderRequest request = new CancelOrderRequest();
            request.setTxHash(txHash);

            CancelOrderResponse response = client.execute(request);
            if(!response.getSuccess()){
                throw new BadRequestException(response.getMessage());
            }
            return response.getData();
        } catch (Exception e) {
            log.error("Cancel chain order failed.. throw exception message:[{}]",e.getMessage());
            throw e;
        }
    }

    public Boolean batchWithdraw(List<WithdrawFlow> withdrawFlows,String chain,String tokenName,String fromAddress,CallbackTypeEnum typeEnum) throws Exception {

        Client client = WalletService.buildClient();
        try {

            WithdrawRequest request = new WithdrawRequest();
            request.setDatas(withdrawFlows);
            request.setTokenName(tokenName);
            request.setChain(chain);
            request.setFromAddress(fromAddress);
            request.setTxnType(typeEnum.getType());

            WithdrawResponse response = client.execute(request);
            log.info("钱包服务响应体:{}", JSON.toJSONString(response));
            boolean flag = response.getSuccess();
            if(!flag){
                throw new Exception(response.getMessage());
            }
            return flag;
        } catch (Exception e) {
            log.error("Generate wallet address failed. throw exception message:[{}]",e.getMessage());
            throw e;
        }
    }

    /**
     * 获取用户钱包地址信息
     */
    public UserWalletAddress getUserAddressInfo(Long userId) {
        return userWalletAddressMapper.selectByUserId(userId);
    }

    /**
     * 获取推荐燃油费
     */
    public BigDecimal getRecommendGas() throws Exception {

        Client client = WalletService.buildClient();

       try {
           GetGasRequest request = new GetGasRequest();
           GetGasResponse response = client.execute(request);
           if(!response.getSuccess()){
               return null;
           }
           return response.getData().getGas();
       }catch (Exception e){
            log.error("Fetch recommend gas throw error. message:{}",e.getMessage());
            throw e;
       }
    }

    /**
     * 调用钱包服务,钱包之间的ETH转账
     * @param fromAddress  打款地址   (null则代表使用平台钱包打款)
     * @param toAddress    收款地址   (null则代表使用平台钱包收款)
     * @param amount     金额
     */
    public Boolean ethTransfer(String fromAddress,String toAddress, BigDecimal amount,String traceId) throws Exception {
        if(fromAddress == null && toAddress == null) {
            throw new BadRequestException(ExceptionEnum.BAD_REQUEST_ERR);
        }
        Client client = WalletService.buildClient();
        try {
            EthTransferAsyncRequest request = new EthTransferAsyncRequest();
            request.setAddress(toAddress);
            request.setAmount(amount);
            request.setTraceId(traceId);
            request.setFromAddress(fromAddress);

            EthTransferResponse response = client.execute(request);
            if(!response.getSuccess()){
                throw new BadRequestException(response.getMessage());
            }
            return true;
        }catch (Exception e){
            log.error("Eth transfer throw error. message:{}",e.getMessage());
            throw e;
        }
    }
}
